/*
 * Created on Aug 31, 2005
 *
 */
package net.sf.google.talk.eclipse.swt;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

import net.sf.google.talk.eclipse.EclipsePlugin;
import net.sf.google.talk.eclipse.views.OutgoingFileManager;

import org.eclipse.core.runtime.ILog;
import org.eclipse.core.runtime.Status;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.CTabItem;
import org.eclipse.swt.custom.StyleRange;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.DropTarget;
import org.eclipse.swt.dnd.DropTargetEvent;
import org.eclipse.swt.dnd.DropTargetListener;
import org.eclipse.swt.dnd.FileTransfer;
import org.eclipse.swt.dnd.TextTransfer;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.FocusListener;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.KeyListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;
import org.jivesoftware.smack.Chat;
import org.jivesoftware.smack.MessageListener;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.packet.DefaultPacketExtension;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smackx.ChatState;
import org.jivesoftware.smackx.ChatStateManager;
import org.jivesoftware.smackx.packet.ChatStateExtension;

public class Conversation extends Composite implements MessageListener {
	protected static final int IDLE_SECONDS = 2;

	private final ILog log = EclipsePlugin.getDefault().getLog();

	private String user;

	private final StyledText conversationText;

	private final Label tempText;
	
	private final Text sendText;

	public Chat chat;

	private CTabItem tabItem;

	private final Color remoteUserColor = new Color(Display.getCurrent(), 255, 0, 0);

	private final Color localUserColor = new Color(Display.getCurrent(), 0, 0, 255);

	private final Label statusLabel;

	private ChatStateManager chatStateManager;
	
	private Boolean isWritting;
	
	private String temp = "";

	private long lastKeyPress;

	public Conversation(final Composite parent, final int style) {
		super(parent, style);
		setLayout(new GridLayout(1, true));
		conversationText = new StyledText(this, SWT.MULTI | SWT.READ_ONLY | SWT.NO_FOCUS | SWT.V_SCROLL);
		conversationText.setJustify(true);
		conversationText.setWordWrap(true);
		conversationText.setLayoutData(new GridData(GridData.FILL_BOTH));

		// texte temporaire
		//tempText = new StyledText(this, SWT.READ_ONLY | SWT.NO_FOCUS | SWT.V_SCROLL);
		tempText = new Label(this, SWT.HORIZONTAL);
		tempText.setForeground(new Color(getDisplay(), new RGB(100, 100, 100)));
		tempText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
		
		// texte de saisie
		sendText = new Text(this, SWT.NONE);
		sendText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
		sendText.addKeyListener(new KeyListener() {

			public void keyPressed(final KeyEvent e) {
				
				// on a forcément le focus 
				resetUglyBackground();
				
				lastKeyPress = System.currentTimeMillis();
				if (e.keyCode == SWT.CR || e.keyCode == SWT.KEYPAD_CR) {
					
					String line = sendText.getText();
					
					isWritting = false;	
					temp = "";
					
					System.out.println("line: " + line);
					if (line != null && line.length() > 0) {
						try {
							// envoi du message
							chat.sendMessage(line);
						} catch (final XMPPException ex) {
							log.log(new Status(Status.ERROR, EclipsePlugin.ID, Status.OK, "Error sending message", ex));
						}
						sendText.setText("");
						int start = conversationText.getCharCount();
						if (start > 0) {
							start--;
						}
						final String local = formatUser(user) + ": ";
						conversationText.append(local);
						final StyleRange r = new StyleRange(start, local.length(), localUserColor, conversationText.getBackground());
						conversationText.setStyleRange(r);
						conversationText.append(line + SWT.LF);
						scroll();
					}
				} else {
					// on est en train d'écrire
					Character car = e.character;
					if (Character.isLetter(car)) {
						temp = sendText.getText()+car;						
					} else {
						temp = sendText.getText();
					}
					try {
						//chat.sendMessage("--"+temp);
						Message messToSend = new Message();
						messToSend.setFrom(user);
						messToSend.setTo(chat.getParticipant());
						//messToSend.setType(Type.normal);
						
						// PacketExtension
						DefaultPacketExtension ext = new DefaultPacketExtension("mess", "gtalk-eclipse");
						ext.setValue("tempo", temp);
						messToSend.addExtension(ext);
						
						// composing extension
						ChatStateExtension chatExt = new ChatStateExtension(ChatState.composing);
						messToSend.addExtension(chatExt);
						
						chat.sendMessage(messToSend);
						
						//System.out.println(messToSend.toXML());
						
						
					} catch (XMPPException e1) {
						e1.printStackTrace();
					}					
				}
			}

			public void keyReleased(final KeyEvent e) {
			}
		});

		this.statusLabel = new Label(parent, SWT.HORIZONTAL | SWT.LEFT);
		this.statusLabel.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
		this.statusLabel.setText("status");
		final Timer t = new Timer();
		t.schedule(new TimerTask() {
			@Override
			public void run() {
				if ((System.currentTimeMillis() - lastKeyPress) > (IDLE_SECONDS * 1000)) {
					setState(ChatState.active);
				} else {
					setState(ChatState.composing);
				}
			}
		}, 0, 500);

		addFocusListener(new FocusListener() {
			public void focusGained(final FocusEvent arg0) {
				System.out.println("FOCUS");
				sendText.setFocus();
			}

			public void focusLost(final FocusEvent arg0) {
			}
		});

		addDropSupport();
	}

	private void addDropSupport() {
		// drop support
		final DropTarget target = new DropTarget(conversationText, DND.DROP_MOVE | DND.DROP_COPY | DND.DROP_DEFAULT);

		final TextTransfer textTransfer = TextTransfer.getInstance();
		final FileTransfer fileTransfer = FileTransfer.getInstance();
		final Transfer[] types = new Transfer[] { fileTransfer, textTransfer };
		target.setTransfer(types);

		target.addDropListener(new DropTargetListener() {
			public void dragEnter(final DropTargetEvent event) {
				System.out.println("dragEnter: " + event);
			}

			public void dragLeave(final DropTargetEvent event) {
			}

			public void dragOperationChanged(final DropTargetEvent event) {
			}

			public void dragOver(final DropTargetEvent event) {
			}

			public void drop(final DropTargetEvent event) {
				if (textTransfer.isSupportedType(event.currentDataType)) {
					final String s = (String) event.data;
					System.out.println("TEXT: " + s);
					// TODO Auto-generated method stub
				}
				if (fileTransfer.isSupportedType(event.currentDataType)) {
					final String[] files = (String[]) event.data;
					for (int i = 0; i < files.length; i++) {
						sendFile(files[i]);
					}
				}
			}

			public void dropAccept(final DropTargetEvent event) {
				// TODO Auto-generated method stub
			}
		});
	}

	public void sendFile(final String filename) {
		System.out.println("TO: " + chat.getParticipant());
		OutgoingFileManager.getInstance().send(filename, chat.getParticipant());
	}

	public void setChat(final Chat aChat) {
		this.chat = aChat;
		this.tabItem.setText("" + formatUser(aChat.getParticipant()));
		this.tabItem.setData(this.chat);
		//sendText.setFocus();
	}

	public void setTabItem(final CTabItem i) {
		this.tabItem = i;
	}

	@Override
	public void dispose() {
		//        receiver.stopListening();
		super.dispose();
	}

	/**
	 * Gets the conversationText.
	 * 
	 * @return Returns the conversationText.
	 * @deprecated
	 * @see #received(String)
	 */
	@Deprecated
	public StyledText getConversationText() {
		return conversationText;
	}

	public void received(final String body) {
		
		System.out.println("receive !!");
		

		// on nous a envoyé du texte
		tempText.setText("");
		int start = conversationText.getCharCount();
		if (start > 0) {
			start--;
		}
		// calcul de l'heure
		Date heure = new Date();
		heure.getTime();
		SimpleDateFormat sdf = new SimpleDateFormat("hh:mm:ss" );
		
		final String participant = formatUser(chat.getParticipant()) + " ("+sdf.format(heure)+") : ";
		conversationText.append(participant);
		final StyleRange r = new StyleRange(start, participant.length(), remoteUserColor, conversationText.getBackground());
		conversationText.setStyleRange(r);
		conversationText.append(body + SWT.LF);
		scroll();

		resetComposing();
		
	}

	/**
	 * 
	 */
	private void scroll() {
		conversationText.setSelection(conversationText.getCharCount() - 1);
		conversationText.showSelection();
	}

	/**
	 * Gets the user.
	 * 
	 * @return Returns the user.
	 */
	public String getUser() {
		return user;
	}

	public String formatUser(final String u) {
		return u.substring(0, u.indexOf('@'));
	}

	/**
	 * Sets the user
	 *
	 * @param user The user to set.
	 */
	public void setUser(final String user) {
		this.user = user;
	}

	public void processMessage(final Chat arg0, final Message arg1) {
		System.out.println("Message: " + arg1);
	}

	public void setChatStateManager(final ChatStateManager instance) {
		this.chatStateManager = instance;
	}

	private void setState(final ChatState s) {
		if (chatStateManager != null) {
			try {
				chatStateManager.setCurrentState(s, chat);
			} catch (final Exception unused) {
			}
		}
	}
	
	/**
	 * permet d'indiquer que le correspondant est en train de composer un message
	 */
	public void setComposing() {
		tempText.setText(formatUser(chat.getParticipant())+ " est en train de composer un message ...");
	}
	
	/**
	 * permet d'indiquer que le correspondant écrit et affiche ce qu'il écrit
	 * @param text
	 */
	public void setComposing(String text) {
		tempText.setText(formatUser(chat.getParticipant())+ " ecrit : "+text);
	}
	
	public void resetComposing() {
		tempText.setText("");
	}
	
	public void setUglyBackground() {
		this.setBackground(new Color(getShell().getDisplay(), new RGB(255, 217, 167)));
	}
	
	public void resetUglyBackground() {
		//this.setBackground(new Color(getShell().getDisplay(), new RGB(255, 255, 255)));
		this.setBackground(null);
		this.redraw();
	}
}
